// Copyright (c) 2017 Personal (Binbin Zhang)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "frontend/feature_pipeline.h"

#include <algorithm>
#include <utility>
DEFINE_bool(is_debug, false, "");
namespace wenet {

FeaturePipeline::FeaturePipeline(const FeaturePipelineConfig& config)
    : config_(config),
      feature_dim_(config.num_bins),
      fbank_(config.num_bins, config.sample_rate, config.frame_length,
             config.frame_shift, config.low_freq, config.pre_emphasis,
             config.scale_input_to_unit, config.log_floor, config.log_base,
             config.window_type, config.mel_type, config.norm_type),
      num_frames_(0),
      input_finished_(false) {}

void FeaturePipeline::AcceptWaveform(const float* pcm, const int size) {
  std::vector<std::vector<float>> feats;
  std::vector<float> waves;
  //一开始剩余wav为空, 所有啥也不添加
  waves.insert(waves.end(), remained_wav_.begin(), remained_wav_.end());
  //将读取的pcm写入waves, size 是读取pcm后得到的长度,肯定是一样的.经过打印也确认,size就是音频的长度.
  waves.insert(waves.end(), pcm, pcm + size);
  if (FLAGS_is_debug){
    std::cout <<"----------------------------wav 归一化前------------------start" << std::endl;
    std::cout << "向量waves的长度为: " << waves.size() << std::endl;
    std::cout << "前20个元素: " << std::endl;
    int num_to_print = std::min(20, static_cast<int>(waves.size()));  // 获取实际要打印的元素个数，避免越界
    for (int i = 0; i < num_to_print; ++i) {
        std::cout << waves[i] << " ";
    }
    std::cout << std::endl;
    std::cout << "-----------wav------------------end" << std::endl;
  }
  //归一化之后的wav做fbank就和Python基本一致了
  bool is_32_pcm = false;
  if (waves[0] > 32767 || waves[0] < -32768){
    is_32_pcm = true;
  }
  std::cout << "is_32_pcm: " << is_32_pcm << std::endl;
  for (size_t i = 0; i < waves.size(); ++i) {
        if (is_32_pcm){
          waves[i] /= 32767.0;
          waves[i] /= 32767.0;
          waves[i] /= 2;
        }else{
          waves[i] /= 32768.0;
        }
  }
  if (FLAGS_is_debug){
    std::cout <<"----------------------------wav 归一化后------------------start" << std::endl;
    std::cout << "向量waves的长度为: " << waves.size() << std::endl;
    std::cout << "前20个元素: " << std::endl;
    int num_to_print2 = std::min(20, static_cast<int>(waves.size()));  // 获取实际要打印的元素个数，避免越界
    for (int i = 0; i < num_to_print2; ++i) {
        std::cout << waves[i] << " ";
    }
    std::cout << std::endl;
    std::cout << "-----------wav------------------end" << std::endl;
  }

  int num_frames = fbank_.Compute(waves, &feats);

  if (FLAGS_is_debug){
    std::cout <<"----------fbank------------------start" << std::endl;
    std::cout << "向量feats的长度为: " << feats.size() << std::endl;
    std::cout << "第一帧的元素: " << std::endl;
    int num_to_print3 = std::min(80, static_cast<int>(feats.size()));  // 获取实际要打印的元素个数，避免越界
    for (int i = 0; i < num_to_print3; ++i) {
        std::cout << feats[0][i] << " ";
    }
    std::cout << std::endl;
    std::cout << "-----------fbank------------------end" << std::endl;
  }
  //将这次音频读取的内容传如特征队列
  feature_queue_.Push(std::move(feats));
  num_frames_ += num_frames;
  // 计算剩余的wav, 并将其存入remained_wav_, 这里的剩余是 把音频的总长度减去计算帧数的内容
  int left_samples = waves.size() - config_.frame_shift * num_frames;
  if( left_samples >= 0) {
    // 剩余wav的size设置为新的采样点数
  remained_wav_.resize(left_samples);
  //将本次wave的剩余内容复制到remained_wav_
  std::copy(waves.begin() + config_.frame_shift * num_frames, waves.end(),
            remained_wav_.begin());
  }
  // We are still adding wave, notify input is not finished
  finish_condition_.notify_one();
}

void FeaturePipeline::AcceptWaveform(const int16_t* pcm, const int size) {
  auto* float_pcm = new float[size];
  // 没懂,直接将int16应转为float
  for (size_t i = 0; i < size; i++) {
    float_pcm[i] = static_cast<float>(pcm[i]);
  }
  this->AcceptWaveform(float_pcm, size);
  delete[] float_pcm;
}

void FeaturePipeline::set_input_finished() {
  CHECK(!input_finished_);
  {
    std::lock_guard<std::mutex> lock(mutex_);
    input_finished_ = true;
  }
  finish_condition_.notify_one();
}

bool FeaturePipeline::ReadOne(std::vector<float>* feat) {
  if (!feature_queue_.Empty()) {
    *feat = std::move(feature_queue_.Pop());
    return true;
  } else {
    std::unique_lock<std::mutex> lock(mutex_);
    while (!input_finished_) {
      // This will release the lock and wait for notify_one()
      // from AcceptWaveform() or set_input_finished()
      finish_condition_.wait(lock);
      if (!feature_queue_.Empty()) {
        *feat = std::move(feature_queue_.Pop());
        return true;
      }
    }
    CHECK(input_finished_);
    // Double check queue.empty, see issue#893 for detailed discussions.
    if (!feature_queue_.Empty()) {
      *feat = std::move(feature_queue_.Pop());
      return true;
    } else {
      return false;
    }
  }
}

bool FeaturePipeline::Read(int num_frames,
                           std::vector<std::vector<float>>* feats) {
  feats->clear();
  if (feature_queue_.Size() >= num_frames) {
    *feats = std::move(feature_queue_.Pop(num_frames));
    return true;
  } else {
    std::unique_lock<std::mutex> lock(mutex_);
    while (!input_finished_) {
      // This will release the lock and wait for notify_one()
      // from AcceptWaveform() or set_input_finished()
      finish_condition_.wait(lock);
      if (feature_queue_.Size() >= num_frames) {
        *feats = std::move(feature_queue_.Pop(num_frames));
        return true;
      }
    }
    CHECK(input_finished_);
    // Double check queue.empty, see issue#893 for detailed discussions.
    if (feature_queue_.Size() >= num_frames) {
      *feats = std::move(feature_queue_.Pop(num_frames));
      return true;
    } else {
      *feats = std::move(feature_queue_.Pop(feature_queue_.Size()));
      return false;
    }
  }
}

void FeaturePipeline::Reset() {
  input_finished_ = false;
  num_frames_ = 0;
  remained_wav_.clear();
  feature_queue_.Clear();
}

}  // namespace wenet
